{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from matplotlib import rc, rcParams\n",
    "rc('axes', linewidth=5)\n",
    "\n",
    "from remat.core.dfgraph import gen_linear_graph\n",
    "from experiments.common.load_keras_model import get_keras_model, CHAIN_GRAPH_MODELS, SEGMENTATION_MODEL_NAMES\n",
    "from remat.core.solvers.strategy_checkpoint_all import solve_checkpoint_all\n",
    "from remat.tensorflow2.extraction import dfgraph_from_keras\n",
    "from remat.core.solvers.strategy_chen import solve_chen_sqrtn, solve_chen_greedy\n",
    "from remat.core.solvers.strategy_optimal_ilp import solve_ilp_gurobi\n",
    "from remat.core.solvers.strategy_griewank import solve_griewank\n",
    "\n",
    "import tensorflow as tf\n",
    "import tensorflow.keras as keras\n",
    "from tensorflow.keras.layers import LayerNormalization, Dense, Activation, Lambda, Reshape\n",
    "\n",
    "sns.set('talk')\n",
    "sns.set_style('white')\n",
    "RED = \"#e74c3c\"\n",
    "BLUE = \"#3498db\"\n",
    "flatui = [RED, BLUE, \"#95a5a6\", \"#e74c3c\", \"#34495e\", \"#2ecc71\"]\n",
    "sns.set_palette(flatui)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "block1_conv1 ['input_35']\n",
      "block1_conv2 ['block1_conv1']\n",
      "block1_pool ['block1_conv2']\n",
      "block2_conv1 ['block1_pool']\n",
      "block2_conv2 ['block2_conv1']\n",
      "block2_pool ['block2_conv2']\n",
      "block3_conv1 ['block2_pool']\n",
      "block3_conv2 ['block3_conv1']\n",
      "block3_conv3 ['block3_conv2']\n",
      "block3_conv4 ['block3_conv3']\n",
      "block3_pool ['block3_conv4']\n",
      "block4_conv1 ['block3_pool']\n",
      "block4_conv2 ['block4_conv1']\n",
      "block4_conv3 ['block4_conv2']\n",
      "block4_conv4 ['block4_conv3']\n",
      "block4_pool ['block4_conv4']\n",
      "block5_conv1 ['block4_pool']\n",
      "block5_conv2 ['block5_conv1']\n",
      "block5_conv3 ['block5_conv2']\n",
      "block5_conv4 ['block5_conv3']\n",
      "block5_pool ['block5_conv4']\n",
      "flatten ['block5_pool']\n",
      "fc1 ['flatten']\n",
      "fc2 ['fc1']\n",
      "predictions ['fc2']\n",
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]\n",
      "Parameter LogToConsole unchanged\n",
      "   Value: 1  Min: 0  Max: 1  Default: 1\n",
      "Parameter LogFile unchanged\n",
      "   Value:   Default: \n",
      "Changed value of parameter Threads to 12\n",
      "   Prev: 0  Min: 0  Max: 1024  Default: 0\n",
      "Parameter TimeLimit unchanged\n",
      "   Value: inf  Min: 0.0  Max: inf  Default: inf\n",
      "Changed value of parameter OptimalityTol to 0.0001\n",
      "   Prev: 1e-06  Min: 1e-09  Max: 0.01  Default: 1e-06\n",
      "Parameter IntFeasTol unchanged\n",
      "   Value: 1e-05  Min: 1e-09  Max: 0.1  Default: 1e-05\n",
      "Changed value of parameter Presolve to 2\n",
      "   Prev: -1  Min: -1  Max: 2  Default: -1\n",
      "Changed value of parameter StartNodeLimit to 10000000\n",
      "   Prev: -1  Min: -2  Max: 2000000000  Default: -1\n",
      "Changed value of parameter TimeLimit to 300.0\n",
      "   Prev: inf  Min: 0.0  Max: inf  Default: inf\n",
      "Gurobi Optimizer version 9.0.1 build v9.0.1rc0 (mac64)\n",
      "Optimize a model with 27726 rows, 12852 columns and 85665 nonzeros\n",
      "Model fingerprint: 0x565886ca\n",
      "Variable types: 2601 continuous, 10251 integer (10251 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 3e+06]\n",
      "  Objective range  [1e+02, 1e+05]\n",
      "  Bounds range     [1e+00, 1e+07]\n",
      "  RHS range        [1e+00, 1e+07]\n",
      "Presolve removed 23537 rows and 9241 columns\n",
      "Presolve time: 0.13s\n",
      "Presolved: 4189 rows, 3611 columns, 14634 nonzeros\n",
      "Variable types: 0 continuous, 3611 integer (2397 binary)\n",
      "Presolve removed 131 rows and 128 columns\n",
      "Presolved: 4058 rows, 3483 columns, 14296 nonzeros\n",
      "\n",
      "\n",
      "Root relaxation: objective 2.207621e+06, 1535 iterations, 0.05 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "*    0     0               0    2207620.5177 2207620.52  0.00%     -    0s\n",
      "\n",
      "Explored 0 nodes (3067 simplex iterations) in 0.29 seconds\n",
      "Thread count was 12 (of 12 available processors)\n",
      "\n",
      "Solution count 1: 2.20762e+06 \n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 2.207620517745e+06, best bound 2.207620517745e+06, gap 0.0000%\n",
      "Changed value of parameter TimeLimit to inf\n",
      "   Prev: 300.0  Min: 0.0  Max: inf  Default: inf\n",
      "\n",
      "\n",
      "Restarting solve\n",
      "\n",
      "\n",
      "Gurobi Optimizer version 9.0.1 build v9.0.1rc0 (mac64)\n",
      "Optimize a model with 25503 rows, 12852 columns and 83442 nonzeros\n",
      "Model fingerprint: 0x85663ec6\n",
      "Variable types: 2601 continuous, 10251 integer (10251 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 3e+06]\n",
      "  Objective range  [1e+02, 1e+05]\n",
      "  Bounds range     [1e+00, 1e+07]\n",
      "  RHS range        [1e+00, 1e+07]\n",
      "\n",
      "MIP start from previous solve produced solution with objective 2.20762e+06 (0.03s)\n",
      "Loaded MIP start from previous solve with objective 2.20762e+06\n",
      "\n",
      "Presolve removed 17841 rows and 7327 columns\n",
      "Presolve time: 0.08s\n",
      "Presolved: 7662 rows, 5525 columns, 28718 nonzeros\n",
      "Variable types: 0 continuous, 5525 integer (4229 binary)\n",
      "Presolve removed 59 rows and 59 columns\n",
      "Presolved: 7603 rows, 5466 columns, 28600 nonzeros\n",
      "\n",
      "\n",
      "Root relaxation: objective 1.796112e+06, 2658 iterations, 0.10 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0 1796112.22    0  218 2207620.52 1796112.22  18.6%     -    0s\n",
      "H    0     0                    1797020.9167 1796112.22  0.05%     -    0s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 39\n",
      "  Cover: 22\n",
      "  Clique: 1\n",
      "  MIR: 15\n",
      "  StrongCG: 7\n",
      "  Zero half: 5\n",
      "  RLT: 6\n",
      "  Relax-and-lift: 28\n",
      "\n",
      "Explored 1 nodes (8542 simplex iterations) in 0.55 seconds\n",
      "Thread count was 12 (of 12 available processors)\n",
      "\n",
      "Solution count 2: 1.79702e+06 2.20762e+06 \n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 1.797020916696e+06, best bound 1.797020916696e+06, gap 0.0000%\n",
      "58.896187392 81.723296\n",
      "72.512667648 69.447584\n",
      "97.082048512 51.380224\n",
      "58.98289152 51.380224\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x576 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_matrix(R, ax, title=None):\n",
    "    ax.invert_yaxis()\n",
    "    ax.pcolormesh(R, cmap=\"Greys\", vmin=0, vmax=1)\n",
    "    ax.set_title(title)\n",
    "\n",
    "def solve_models(g):\n",
    "    checkpoint_all = solve_checkpoint_all(g)\n",
    "    chen_sqrtn = solve_chen_sqrtn(g, True)\n",
    "    griewank = solve_griewank(g, 5)\n",
    "    optimal = solve_ilp_gurobi(g, griewank.schedule_aux_data.activation_ram, approx=False,\n",
    "                               solve_r=False, seed_s=chen_sqrtn.schedule_aux_data.S)\n",
    "    return checkpoint_all, chen_sqrtn, griewank, optimal\n",
    "    \n",
    "def plot_model(sols):\n",
    "    checkpoint_all, chen_sqrtn, griewank, optimal = sols\n",
    "    fig, axs = plt.subplots(2, 2, figsize=(8, 8))\n",
    "    plot_matrix(checkpoint_all.schedule_aux_data.S, axs[0, 0], title=\"Checkpoint all nodes\")\n",
    "    plot_matrix(chen_sqrtn.schedule_aux_data.S, axs[0, 1], title=\"Chen et al. ($\\sqrt{n}$)\")\n",
    "    plot_matrix(griewank.schedule_aux_data.S, axs[1, 0], title=\"$\\texttt{revolve}$ ($\\log{n}$)\")\n",
    "    plot_matrix(optimal.schedule_aux_data.S, axs[1, 1], title=\"Checkmate (optimal)\")\n",
    "    plt.plot(fig=fig)\n",
    "    return fig\n",
    "\n",
    "model = get_keras_model(\"VGG19\")\n",
    "# g = gen_linear_graph(16)\n",
    "g = dfgraph_from_keras(model)\n",
    "print(g.vfwd)\n",
    "checkpoint_all, chen_sqrtn, griewank, optimal = solve_models(g)\n",
    "fig = plot_model((checkpoint_all, chen_sqrtn, griewank, optimal))\n",
    "fig.savefig('out.pdf', bbox_inches='tight')\n",
    "\n",
    "\n",
    "for method in [checkpoint_all, chen_sqrtn, griewank, optimal]:\n",
    "    aux_data = method.schedule_aux_data\n",
    "    print(aux_data.cpu / 1e9, aux_data.activation_ram / 1e6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "block1_conv1 ['input_36']\n",
      "block1_conv2 ['block1_conv1']\n",
      "block1_pool ['block1_conv2']\n",
      "block2_conv1 ['block1_pool']\n",
      "block2_conv2 ['block2_conv1']\n",
      "block2_pool ['block2_conv2']\n",
      "block3_conv1 ['block2_pool']\n",
      "block3_conv2 ['block3_conv1']\n",
      "block3_conv3 ['block3_conv2']\n",
      "block3_conv4 ['block3_conv3']\n",
      "block3_pool ['block3_conv4']\n",
      "block4_conv1 ['block3_pool']\n",
      "block4_conv2 ['block4_conv1']\n",
      "block4_conv3 ['block4_conv2']\n",
      "block4_conv4 ['block4_conv3']\n",
      "block4_pool ['block4_conv4']\n",
      "block5_conv1 ['block4_pool']\n",
      "block5_conv2 ['block5_conv1']\n",
      "block5_conv3 ['block5_conv2']\n",
      "block5_conv4 ['block5_conv3']\n",
      "block5_pool ['block5_conv4']\n",
      "flatten ['block5_pool']\n",
      "fc1 ['flatten']\n",
      "fc2 ['fc1']\n",
      "predictions ['fc2']\n",
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]\n",
      "Checkpoint all activation ram 81723296\n",
      "Chen activation ram 69447584\n",
      "Griewank activation ram 51380224\n",
      "Parameter LogToConsole unchanged\n",
      "   Value: 1  Min: 0  Max: 1  Default: 1\n",
      "Parameter LogFile unchanged\n",
      "   Value:   Default: \n",
      "Changed value of parameter Threads to 12\n",
      "   Prev: 0  Min: 0  Max: 1024  Default: 0\n",
      "Parameter TimeLimit unchanged\n",
      "   Value: inf  Min: 0.0  Max: inf  Default: inf\n",
      "Changed value of parameter OptimalityTol to 0.0001\n",
      "   Prev: 1e-06  Min: 1e-09  Max: 0.01  Default: 1e-06\n",
      "Parameter IntFeasTol unchanged\n",
      "   Value: 1e-05  Min: 1e-09  Max: 0.1  Default: 1e-05\n",
      "Changed value of parameter Presolve to 2\n",
      "   Prev: -1  Min: -1  Max: 2  Default: -1\n",
      "Changed value of parameter StartNodeLimit to 10000000\n",
      "   Prev: -1  Min: -2  Max: 2000000000  Default: -1\n",
      "Changed value of parameter TimeLimit to 300.0\n",
      "   Prev: inf  Min: 0.0  Max: inf  Default: inf\n",
      "Gurobi Optimizer version 9.0.1 build v9.0.1rc0 (mac64)\n",
      "Optimize a model with 27726 rows, 12852 columns and 85665 nonzeros\n",
      "Model fingerprint: 0x8f071ac6\n",
      "Variable types: 2601 continuous, 10251 integer (10251 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 3e+06]\n",
      "  Objective range  [1e+02, 1e+05]\n",
      "  Bounds range     [1e+00, 1e+07]\n",
      "  RHS range        [1e+00, 1e+07]\n",
      "Presolve removed 23537 rows and 9241 columns\n",
      "Presolve time: 0.12s\n",
      "Presolved: 4189 rows, 3611 columns, 14634 nonzeros\n",
      "Variable types: 0 continuous, 3611 integer (2397 binary)\n",
      "Presolve removed 131 rows and 128 columns\n",
      "Presolved: 4058 rows, 3483 columns, 14296 nonzeros\n",
      "\n",
      "\n",
      "Root relaxation: objective 2.208196e+06, 1523 iterations, 0.05 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0 2208195.63    0    1          - 2208195.63      -     -    0s\n",
      "H    0     0                    2208195.6304 2208195.63  0.00%     -    0s\n",
      "\n",
      "Explored 1 nodes (3160 simplex iterations) in 0.29 seconds\n",
      "Thread count was 12 (of 12 available processors)\n",
      "\n",
      "Solution count 1: 2.2082e+06 \n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 2.208195630386e+06, best bound 2.208195630386e+06, gap 0.0000%\n",
      "Changed value of parameter TimeLimit to inf\n",
      "   Prev: 300.0  Min: 0.0  Max: inf  Default: inf\n",
      "\n",
      "\n",
      "Restarting solve\n",
      "\n",
      "\n",
      "Gurobi Optimizer version 9.0.1 build v9.0.1rc0 (mac64)\n",
      "Optimize a model with 25503 rows, 12852 columns and 83442 nonzeros\n",
      "Model fingerprint: 0xf0024054\n",
      "Variable types: 2601 continuous, 10251 integer (10251 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 3e+06]\n",
      "  Objective range  [1e+02, 1e+05]\n",
      "  Bounds range     [1e+00, 1e+07]\n",
      "  RHS range        [1e+00, 1e+07]\n",
      "\n",
      "MIP start from previous solve produced solution with objective 2.2082e+06 (0.02s)\n",
      "Loaded MIP start from previous solve with objective 2.2082e+06\n",
      "\n",
      "Presolve removed 17841 rows and 7327 columns\n",
      "Presolve time: 0.08s\n",
      "Presolved: 7662 rows, 5525 columns, 28718 nonzeros\n",
      "Variable types: 0 continuous, 5525 integer (4229 binary)\n",
      "Presolve removed 59 rows and 59 columns\n",
      "Presolved: 7603 rows, 5466 columns, 28600 nonzeros\n",
      "\n",
      "\n",
      "Root relaxation: objective 1.795580e+06, 2734 iterations, 0.09 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0 1795579.86    0  218 2208195.63 1795579.86  18.7%     -    0s\n",
      "H    0     0                    1881101.9648 1795579.86  4.55%     -    0s\n",
      "     0     0 1796489.98    0  283 1881101.96 1796489.98  4.50%     -    0s\n",
      "H    0     0                    1852521.9966 1796489.98  3.02%     -    0s\n",
      "H    0     0                    1796489.9800 1796489.98  0.00%     -    0s\n",
      "     0     0 1796489.98    0  288 1796489.98 1796489.98  0.00%     -    0s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 15\n",
      "  Cover: 99\n",
      "  Implied bound: 3\n",
      "  MIR: 28\n",
      "  StrongCG: 8\n",
      "  Zero half: 6\n",
      "  RLT: 15\n",
      "  Relax-and-lift: 13\n",
      "\n",
      "Explored 1 nodes (8623 simplex iterations) in 0.59 seconds\n",
      "Thread count was 12 (of 12 available processors)\n",
      "\n",
      "Solution count 4: 1.79649e+06 1.85252e+06 1.8811e+06 2.2082e+06 \n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 1.796489980020e+06, best bound 1.796489980020e+06, gap 0.0000%\n",
      "optimal activation ram 51380224\n",
      "58.896187392 81.723296\n",
      "72.512667648 69.447584\n",
      "97.082048512 51.380224\n",
      "58.98289152 51.380224\n"
     ]
    },
    {
     "data": {
      "image/png": "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wfLlyzF48GCdXPioaollUbPevHkzWrRogXr16hV6XdWQmOyqVasGIyMj2NvbAwAmTJiAkSNH4qOPPkL//v3xxx9/YOPGjZg+fToqVapUpDJ/+OGHGDFiBP766y80bty4SNsob0oqnnfs2IHo6GgsWrRI67mcOXMmDh06hF27dkkPxpArOcRyUWzduhV169aFUqksk/2rlFU8Ozs7Y+7cudi7d2/pfcZKfWR3Pnbu3Cl69Ogh7OzsRK9evcS+fft0uv179+6JefPmCUdHR2FnZyecnJzEsmXLxMuXL6VlXr58KTp16qTxIAIhhJg1a5Zo3LixCAsLExMmTBAKhULjb8WKFUWeJ8TrAfsKhULcunVLfPXVV6Jjx47C2tpaRERECCGE2Ldvn9b1VX/79+8XQggxZswYoVAohK2trejUqZNYtmyZSEtLE0IIcefOHWFrayvmzp2rdnzR0dFi5syZomPHjsLW1lY4OTmJjRs3iqysLLXlFixYIBQKhXjy5IkQQojPPvtMKBQKkZCQoHHOte2rIO+DNvfv3xdNmjQRP/zwg9r08+fPC4VCIUJCQtSmJyQkiICAANG5c2dha2srOnfuLAICAkRiYqK0zMyZM4WTk5OIjY0VkydPFkqlUjRt2lQolUphY2MjmjRpIrp3765RlsDAQKFQKERcXJxYsmSJcHR0FPb29qJ///7i4sWLasump6eL1q1bi9mzZ+d5fBVNScSzu7u7cHBwkD7L2kRHR6vFrqOjoxg2bJg4cOCA6N27t7C1tRXOzs5ix44dGutGRESIESNGCAcHB+Hg4CBGjhwprly5orHc5cuXxejRo0XLli1F69atxZgxY8Rff/0lzR82bJhwdHSUXqekpIiBAwcKBwcHER4eLoQQwsXFJc9Y9vb2Fq1atRItW7YU7dq1U4vlV69eiR07dkjnw87OTvTs2VOsX79eiteZM2eqbW/YsGFSeaKiosTEiRNFixYtRNOmTYWHh4f47bff8j3/L1++FC1atBBff/21xry//vpLTJgwQbRo0ULY29uLQYMGiRMnTqgtM2zYMOHj4yN++eUX0atXL2Fvby/69u0rjh49Ki2zatUqtXKrzqNqemxsrPTawcFBREVFiREjRohmzZqJpk2bitatW4usrCwRFBQkunbtKpo2bSocHByEjY2N6Natm9i4caMQQohz584JX19f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\n",
      "text/plain": [
       "<Figure size 576x576 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_matrix(R, ax, title=None):\n",
    "    ax.invert_yaxis()\n",
    "    ax.pcolormesh(R, cmap=\"Greys\", vmin=0, vmax=1)\n",
    "    ax.set_title(title)\n",
    "\n",
    "def solve_models(g):\n",
    "    checkpoint_all = solve_checkpoint_all(g)\n",
    "    print(\"Checkpoint all activation ram\", checkpoint_all.schedule_aux_data.activation_ram)\n",
    "    chen_sqrtn = solve_chen_sqrtn(g, True)\n",
    "    print(\"Chen activation ram\", chen_sqrtn.schedule_aux_data.activation_ram)\n",
    "    griewank = solve_griewank(g, 5)\n",
    "    print(\"Griewank activation ram\", griewank.schedule_aux_data.activation_ram)\n",
    "    optimal = solve_ilp_gurobi(g, griewank.schedule_aux_data.activation_ram, approx=False,\n",
    "                               solve_r=False, seed_s=chen_sqrtn.schedule_aux_data.S)\n",
    "    print(\"optimal activation ram\", optimal.schedule_aux_data.activation_ram)\n",
    "    return checkpoint_all, chen_sqrtn, griewank, optimal\n",
    "    \n",
    "def plot_model(sols):\n",
    "    checkpoint_all, chen_sqrtn, griewank, optimal = sols\n",
    "    fig, axs = plt.subplots(2, 2, figsize=(8, 8))\n",
    "    plot_matrix(checkpoint_all.schedule_aux_data.R, axs[0, 0], title=\"Checkpoint all nodes\")\n",
    "    plot_matrix(chen_sqrtn.schedule_aux_data.R, axs[0, 1], title=\"Chen et al. ($\\sqrt{n}$)\")\n",
    "    plot_matrix(griewank.schedule_aux_data.R, axs[1, 0], title=\"$\\texttt{revolve}$ ($\\log{n}$)\")\n",
    "    plot_matrix(optimal.schedule_aux_data.R, axs[1, 1], title=\"Checkmate (optimal)\")\n",
    "    plt.plot(fig=fig)\n",
    "    return fig\n",
    "\n",
    "model = get_keras_model(\"VGG19\")\n",
    "# g = gen_linear_graph(16)\n",
    "g = dfgraph_from_keras(model)\n",
    "print(g.vfwd)\n",
    "checkpoint_all, chen_sqrtn, griewank, optimal = solve_models(g)\n",
    "fig = plot_model((checkpoint_all, chen_sqrtn, griewank, optimal))\n",
    "fig.savefig('out.pdf', bbox_inches='tight')\n",
    "\n",
    "\n",
    "for method in [checkpoint_all, chen_sqrtn, griewank, optimal]:\n",
    "    aux_data = method.schedule_aux_data\n",
    "    print(aux_data.cpu / 1e9, aux_data.activation_ram / 1e6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "block1_conv1 ['input_30']\n",
      "block1_conv2 ['block1_conv1']\n",
      "block1_pool ['block1_conv2']\n",
      "block2_conv1 ['block1_pool']\n",
      "block2_conv2 ['block2_conv1']\n",
      "block2_pool ['block2_conv2']\n",
      "block3_conv1 ['block2_pool']\n",
      "block3_conv2 ['block3_conv1']\n",
      "block3_conv3 ['block3_conv2']\n",
      "block3_conv4 ['block3_conv3']\n",
      "block3_pool ['block3_conv4']\n",
      "block4_conv1 ['block3_pool']\n",
      "block4_conv2 ['block4_conv1']\n",
      "block4_conv3 ['block4_conv2']\n",
      "block4_conv4 ['block4_conv3']\n",
      "block4_pool ['block4_conv4']\n",
      "block5_conv1 ['block4_pool']\n",
      "block5_conv2 ['block5_conv1']\n",
      "block5_conv3 ['block5_conv2']\n",
      "block5_conv4 ['block5_conv3']\n",
      "block5_pool ['block5_conv4']\n",
      "flatten ['block5_pool']\n",
      "fc1 ['flatten']\n",
      "fc2 ['fc1']\n",
      "predictions ['fc2']\n",
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]\n",
      "Checkpoint all activation ram 81723296\n",
      "Chen activation ram 69447584\n",
      "Griewank activation ram 51380224\n",
      "Parameter LogToConsole unchanged\n",
      "   Value: 1  Min: 0  Max: 1  Default: 1\n",
      "Parameter LogFile unchanged\n",
      "   Value:   Default: \n",
      "Changed value of parameter Threads to 12\n",
      "   Prev: 0  Min: 0  Max: 1024  Default: 0\n",
      "Parameter TimeLimit unchanged\n",
      "   Value: inf  Min: 0.0  Max: inf  Default: inf\n",
      "Changed value of parameter OptimalityTol to 0.0001\n",
      "   Prev: 1e-06  Min: 1e-09  Max: 0.01  Default: 1e-06\n",
      "Parameter IntFeasTol unchanged\n",
      "   Value: 1e-05  Min: 1e-09  Max: 0.1  Default: 1e-05\n",
      "Changed value of parameter Presolve to 2\n",
      "   Prev: -1  Min: -1  Max: 2  Default: -1\n",
      "Changed value of parameter StartNodeLimit to 10000000\n",
      "   Prev: -1  Min: -2  Max: 2000000000  Default: -1\n",
      "Changed value of parameter TimeLimit to 300.0\n",
      "   Prev: inf  Min: 0.0  Max: inf  Default: inf\n",
      "Gurobi Optimizer version 9.0.1 build v9.0.1rc0 (mac64)\n",
      "Optimize a model with 27726 rows, 12852 columns and 85665 nonzeros\n",
      "Model fingerprint: 0xe74bf600\n",
      "Variable types: 2601 continuous, 10251 integer (10251 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 3e+06]\n",
      "  Objective range  [1e+02, 1e+05]\n",
      "  Bounds range     [1e+00, 1e+07]\n",
      "  RHS range        [1e+00, 1e+07]\n",
      "Presolve removed 23537 rows and 9241 columns\n",
      "Presolve time: 0.12s\n",
      "Presolved: 4189 rows, 3611 columns, 14634 nonzeros\n",
      "Variable types: 0 continuous, 3611 integer (2397 binary)\n",
      "Presolve removed 131 rows and 128 columns\n",
      "Presolved: 4058 rows, 3483 columns, 14296 nonzeros\n",
      "\n",
      "\n",
      "Root relaxation: objective 2.204236e+06, 1505 iterations, 0.05 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0 2204236.13    0    1          - 2204236.13      -     -    0s\n",
      "H    0     0                    2204236.1325 2204236.13  0.00%     -    0s\n",
      "\n",
      "Explored 1 nodes (3050 simplex iterations) in 0.29 seconds\n",
      "Thread count was 12 (of 12 available processors)\n",
      "\n",
      "Solution count 1: 2.20424e+06 \n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 2.204236132503e+06, best bound 2.204236132503e+06, gap 0.0000%\n",
      "Changed value of parameter TimeLimit to inf\n",
      "   Prev: 300.0  Min: 0.0  Max: inf  Default: inf\n",
      "\n",
      "\n",
      "Restarting solve\n",
      "\n",
      "\n",
      "Gurobi Optimizer version 9.0.1 build v9.0.1rc0 (mac64)\n",
      "Optimize a model with 25503 rows, 12852 columns and 83442 nonzeros\n",
      "Model fingerprint: 0xd2a386ed\n",
      "Variable types: 2601 continuous, 10251 integer (10251 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 3e+06]\n",
      "  Objective range  [1e+02, 1e+05]\n",
      "  Bounds range     [1e+00, 1e+07]\n",
      "  RHS range        [1e+00, 1e+07]\n",
      "\n",
      "MIP start from previous solve produced solution with objective 2.20424e+06 (0.02s)\n",
      "Loaded MIP start from previous solve with objective 2.20424e+06\n",
      "\n",
      "Presolve removed 17841 rows and 7327 columns\n",
      "Presolve time: 0.08s\n",
      "Presolved: 7662 rows, 5525 columns, 28718 nonzeros\n",
      "Variable types: 0 continuous, 5525 integer (4229 binary)\n",
      "Presolve removed 59 rows and 59 columns\n",
      "Presolved: 7603 rows, 5466 columns, 28600 nonzeros\n",
      "\n",
      "\n",
      "Root relaxation: objective 1.792464e+06, 2813 iterations, 0.09 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0 1792463.61    0  188 2204236.13 1792463.61  18.7%     -    0s\n",
      "     0     0 1793365.73    0  140 2204236.13 1793365.73  18.6%     -    0s\n",
      "H    0     0                    1905597.7977 1793365.73  5.89%     -    0s\n",
      "     0     0 1793365.73    0  162 1905597.80 1793365.73  5.89%     -    0s\n",
      "H    0     0                    1793365.7324 1793365.73  0.00%     -    0s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 33\n",
      "  Cover: 153\n",
      "  Implied bound: 6\n",
      "  Clique: 3\n",
      "  MIR: 32\n",
      "  StrongCG: 11\n",
      "  Zero half: 11\n",
      "  RLT: 19\n",
      "  Relax-and-lift: 14\n",
      "\n",
      "Explored 1 nodes (9198 simplex iterations) in 0.64 seconds\n",
      "Thread count was 12 (of 12 available processors)\n",
      "\n",
      "Solution count 3: 1.79337e+06 1.9056e+06 2.20424e+06 \n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 1.793365732364e+06, best bound 1.793365732364e+06, gap 0.0000%\n",
      "optimal activation ram 51380224\n",
      "58.896187392 81.723296\n",
      "72.512667648 69.447584\n",
      "97.082048512 51.380224\n",
      "58.98289152 51.380224\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x576 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_matrix(R, ax, title=None):\n",
    "    ax.invert_yaxis()\n",
    "    ax.pcolormesh(R, cmap=\"Greys\", vmin=0, vmax=1)\n",
    "    ax.set_title(title)\n",
    "\n",
    "def solve_models(g):\n",
    "    checkpoint_all = solve_checkpoint_all(g)\n",
    "    print(\"Checkpoint all activation ram\", checkpoint_all.schedule_aux_data.activation_ram)\n",
    "    chen_sqrtn = solve_chen_sqrtn(g, True)\n",
    "    print(\"Chen activation ram\", chen_sqrtn.schedule_aux_data.activation_ram)\n",
    "    griewank = solve_griewank(g, 5)\n",
    "    print(\"Griewank activation ram\", griewank.schedule_aux_data.activation_ram)\n",
    "    optimal = solve_ilp_gurobi(g, griewank.schedule_aux_data.activation_ram, approx=False,\n",
    "                               solve_r=True, seed_s=chen_sqrtn.schedule_aux_data.S)\n",
    "    print(\"optimal activation ram\", optimal.schedule_aux_data.activation_ram)\n",
    "    return checkpoint_all, chen_sqrtn, griewank, optimal\n",
    "    \n",
    "def plot_model(sols):\n",
    "    checkpoint_all, chen_sqrtn, griewank, optimal = sols\n",
    "    fig, axs = plt.subplots(2, 2, figsize=(8, 8))\n",
    "    plot_matrix(checkpoint_all.schedule_aux_data.R, axs[0, 0], title=\"Checkpoint all nodes\")\n",
    "    plot_matrix(chen_sqrtn.schedule_aux_data.R, axs[0, 1], title=\"Chen et al. ($\\sqrt{n}$)\")\n",
    "    plot_matrix(griewank.schedule_aux_data.R, axs[1, 0], title=\"$\\texttt{revolve}$ ($\\log{n}$)\")\n",
    "    plot_matrix(optimal.schedule_aux_data.R, axs[1, 1], title=\"Checkmate (optimal)\")\n",
    "    plt.plot(fig=fig)\n",
    "    return fig\n",
    "\n",
    "model = get_keras_model(\"VGG19\")\n",
    "# g = gen_linear_graph(16)\n",
    "g = dfgraph_from_keras(model)\n",
    "print(g.vfwd)\n",
    "checkpoint_all, chen_sqrtn, griewank, optimal = solve_models(g)\n",
    "fig = plot_model((checkpoint_all, chen_sqrtn, griewank, optimal))\n",
    "fig.savefig('out.pdf', bbox_inches='tight')\n",
    "\n",
    "\n",
    "for method in [checkpoint_all, chen_sqrtn, griewank, optimal]:\n",
    "    aux_data = method.schedule_aux_data\n",
    "    print(aux_data.cpu / 1e9, aux_data.activation_ram / 1e6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "58.896187392 81.723296\n",
      "72.512667648 69.447584\n",
      "108.266881024 51.380224\n",
      "58.98289152 51.380224\n"
     ]
    }
   ],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* \u001b[31mc62ac61\u001b[m -\u001b[33m (HEAD -> mlsys20_artifact, origin/mlsys20_artifact)\u001b[m Update README.md \u001b[32m(2 days ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31mc0def2e\u001b[m -\u001b[33m (tag: 0.1.4)\u001b[m Fix issues as cited in reproducibility reviews \u001b[32m(9 days ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31ma91771a\u001b[m -\u001b[33m (tag: 0.1.3)\u001b[m Update README with CPU instructions \u001b[32m(2 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31mb512f72\u001b[m -\u001b[33m (tag: v0.1.1, tag: 0.1.2)\u001b[m Update README.md, add --num-threads \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m4687d0e\u001b[m -\u001b[33m\u001b[m Replace README.md \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m73a0e27\u001b[m -\u001b[33m\u001b[m Fix bug with max BS plotting \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m1d65ec7\u001b[m -\u001b[33m\u001b[m Add artifact instructions \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m06bccf7\u001b[m -\u001b[33m\u001b[m Add dependencies to setup.py \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31mc4d59f0\u001b[m -\u001b[33m\u001b[m Add constraints on Free_E to max BS ILP \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m1d62be7\u001b[m -\u001b[33m\u001b[m Remove approximations from budget sweep \u001b[32m(6 weeks ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m11eaf40\u001b[m -\u001b[33m (tag: v0.1.0)\u001b[m Add integrality gap experiment and LP strategy (#48) \u001b[32m(3 months ago) \u001b[1;34m<Ajay Jain>\u001b[m\n",
      "* \u001b[31m820dc61\u001b[m -\u001b[33m\u001b[m Create table_approx_speedup_ratios.py (#53) \u001b[32m(3 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mde5c706\u001b[m -\u001b[33m\u001b[m Update typo in text, change duplicated symbol in budget sweep (#51) \u001b[32m(3 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mf4cde15\u001b[m -\u001b[33m\u001b[m Linear models for testing approx algos (#50) \u001b[32m(3 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m40c42b1\u001b[m -\u001b[33m\u001b[m Rename sweep \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mbb8691c\u001b[m -\u001b[33m\u001b[m Fix bug in 0.5 deterministic rounding, add randomized rounding approximation strategy (#49) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31md76acfc\u001b[m -\u001b[33m\u001b[m Chart smaller marker \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mdd67b07\u001b[m -\u001b[33m\u001b[m Add 0.5 threshold strategy (#47) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m9285234\u001b[m -\u001b[33m\u001b[m Deterministic rounding with randomly sampled thresholds (#46) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m8c6740e\u001b[m -\u001b[33m\u001b[m Deterministic rounding algorithm for LPs (#41) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m48deb43\u001b[m -\u001b[33m\u001b[m Enable flag to solve the ILP via LP relaxation (#39) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m03fb70d\u001b[m -\u001b[33m\u001b[m Rename package in actions (#37) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mc7b86f8\u001b[m -\u001b[33m\u001b[m Options in extraction for inputs, output and next_output nodes (#32) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m1a152ae\u001b[m -\u001b[33m\u001b[m Update README.md \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m9471c48\u001b[m -\u001b[33m\u001b[m Add citation block \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m5553654\u001b[m -\u001b[33m\u001b[m Misc changes on the way to execution (#30) \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m815102a\u001b[m -\u001b[33m\u001b[m Update README.md \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31me5591dd\u001b[m -\u001b[33m\u001b[m Update README.md \u001b[32m(4 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m5d4674a\u001b[m -\u001b[33m\u001b[m Multi OS testing (#31) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mbc9ee46\u001b[m -\u001b[33m\u001b[m Clean up utils in preparation for extraction refactor (#29) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m3755b89\u001b[m -\u001b[33m\u001b[m Fix max batch size scanning (#27) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mcb4a7b2\u001b[m -\u001b[33m\u001b[m Max batch size experiment (#26) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m200e21e\u001b[m -\u001b[33m\u001b[m Change cache directory (#25) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mf40e26c\u001b[m -\u001b[33m\u001b[m Load profiles from S3 (#24) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m36d504c\u001b[m -\u001b[33m\u001b[m Migrate over old redis cache interface (#20) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mf0cd0d1\u001b[m -\u001b[33m\u001b[m During evaluation, write plots for the extracted keras model graph and the extracted graph (#22) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mfc19414\u001b[m -\u001b[33m\u001b[m Tensorflow 2.0 version bump from beta (#23) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m31057e2\u001b[m -\u001b[33m\u001b[m Ray 0.7.5 official (#21) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m9ec6170\u001b[m -\u001b[33m\u001b[m Bump ray \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31md6c49c5\u001b[m -\u001b[33m\u001b[m [refactor] Migrate budget_sweep (#18) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m084f6ea\u001b[m -\u001b[33m\u001b[m Migration for TF2 extraction code (#16) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31mfe473bc\u001b[m -\u001b[33m\u001b[m Test Chen's solutions (#15) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m893a686\u001b[m -\u001b[33m\u001b[m Test timer class (#14) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m9b14ada\u001b[m -\u001b[33m\u001b[m Move ILP solver and Griewank to remat project (#10) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m658e544\u001b[m -\u001b[33m\u001b[m Add CI badge \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m5df47fb\u001b[m -\u001b[33m\u001b[m Move plotting code to experiments directory (#8) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31ma981458\u001b[m -\u001b[33m\u001b[m Rename solve_strategy (#11) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m1ef812b\u001b[m -\u001b[33m\u001b[m CI (#13) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31md0da9ca\u001b[m -\u001b[33m\u001b[m Refactor core of package to remat package (#1) \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m\n",
      "* \u001b[31m6879686\u001b[m -\u001b[33m\u001b[m Initialize repository from https://github.com/parasj/optimalcheckpointing \u001b[32m(5 months ago) \u001b[1;34m<Paras Jain>\u001b[m"
     ]
    }
   ],
   "source": [
    "!git lg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<remat.core.dfgraph.DFGraph at 0x1f4d072410>"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
